/*
 * Explosion.cpp
 */

#include "Explosion.h"
#include <stdlib.h>
#include <math.h>
#include <windows.h>

Explosion::Explosion(Level *level){
	this->level = level;
	// create particle structure
	particle = new Particle[particle_num];
}

Explosion::~Explosion() {
	delete [] particle;
}

void Explosion::initializeGL(GLuint *texture)
{
	this->texture = texture;
}

bool Explosion::renderGL2()
{
	// set proper setting for light etc.
	glDisable(GL_LIGHTING);
	glDepthMask(GL_FALSE);
	glEnable(GL_TEXTURE_2D);
	glEnable(GL_BLEND);
	glPushMatrix();
	// move to explosion position
	glTranslatef(p_X, p_Y, p_Z);
	// bind the particle texture
	glBindTexture(GL_TEXTURE_2D, texture[0]);
	// go through every particle and draw it 3 times (every time align it differently)
	bool bombStilActive = false;
	for(int i=0; i<particle_num; i++){
		glPushMatrix();
		// move to particle position
		glTranslatef(particle[i].pos_x, particle[i].pos_y, particle[i].pos_z);
		//set color of particle
		glColor4f(particle[i].red, particle[i].green, particle[i].blue, particle[i].alpha);
	    // draw particle aligned with z axes
		glPushMatrix();
		glBegin(GL_TRIANGLE_FAN);
	        glTexCoord2f(0.0,0.0); glVertex3f(0.0-particle[i].size/2,0.0-particle[i].size/2,0.0);
	        glTexCoord2f(1.0,0.0); glVertex3f(particle[i].size-particle[i].size/2,0.0-particle[i].size,0.0);
	        glTexCoord2f(1.0,1.0); glVertex3f(particle[i].size-particle[i].size/2,particle[i].size-particle[i].size/2,0.0);
	        glTexCoord2f(0.0,1.0); glVertex3f(0.0-particle[i].size/2,particle[i].size-particle[i].size/2,0.0);
	    glEnd();
	    glPopMatrix();
	    // draw particle aligned with y axes
	    glPushMatrix();
	    glBegin(GL_TRIANGLE_FAN);
	        glTexCoord2f(0.0,0.0); glVertex3f(0.0,0.0-particle[i].size/2,0.0-particle[i].size/2);
	        glTexCoord2f(1.0,0.0); glVertex3f(0.0,particle[i].size-particle[i].size/2,0.0-particle[i].size/2);
	        glTexCoord2f(1.0,1.0); glVertex3f(0.0,particle[i].size-particle[i].size/2,particle[i].size-particle[i].size/2);
	        glTexCoord2f(0.0,1.0); glVertex3f(0.0,0.0-particle[i].size/2,particle[i].size-particle[i].size/2);
	    glEnd();
	    glPopMatrix();
	    // draw particle aligned with x axes
	    glPushMatrix();
	    glBegin(GL_TRIANGLE_FAN);
	        glTexCoord2f(0.0,0.0); glVertex3f(0.0-particle[i].size/2,0.0,0.0-particle[i].size/2);
	        glTexCoord2f(1.0,0.0); glVertex3f(particle[i].size-particle[i].size/2,0.0,0.0-particle[i].size/2);
	        glTexCoord2f(1.0,1.0); glVertex3f(particle[i].size-particle[i].size/2,0.0,particle[i].size-particle[i].size/2);
	        glTexCoord2f(0.0,1.0); glVertex3f(0.0-particle[i].size/2,0.0,particle[i].size-particle[i].size/2);
	    glEnd();
	    glPopMatrix();
		glPopMatrix();
		// mark that this level location is on fire
		if(particle[i].alpha > 0){
			level->model[(int)(p_X+particle[i].pos_x)][(int)(p_Y+particle[i].pos_y)].isOnFire = true;
			bombStilActive = true;
		}
	}
	glBindTexture(GL_TEXTURE_2D, 0);
	glPopMatrix();
	// reset settings for light etc.
	glEnable(GL_LIGHTING);
	glDepthMask(GL_TRUE);
	glDisable(GL_TEXTURE_2D);
	glDisable(GL_BLEND);
	return bombStilActive;
}

void Explosion::update(float miliseconds){
	float new_explosion_diameter = explosion_diameter + 0.012*miliseconds;
	for(int i=0; i<particle_num; i++){
		if(fabs(particle[i].pos_y) > explosion_diameter && fabs(particle[i].pos_y) <= new_explosion_diameter || fabs(particle[i].pos_x) > explosion_diameter && fabs(particle[i].pos_x) <= new_explosion_diameter){
			particle[i].alpha = 0.5;
		}
		else{
			particle[i].alpha -= 0.001*miliseconds;
		}
	}
	explosion_diameter = new_explosion_diameter;
}

void Explosion::setPosition(float x, float y, float z, int size){
	this->p_X = x;
	this->p_Y = y;
	this->p_Z = z;
	explosion_diameter = 0.1;
	for(int i=0; i<particle_num; i++){
		// horizontal part of the cross
		if(i%2 == 0){
			particle[i].pos_x = rand()%(size*2200)*0.001-size*1.1;
			particle[i].pos_y = rand()%100*0.001;
		}
		// vertical part of the cross
		else{
			particle[i].pos_x = rand()%100*0.001;
			particle[i].pos_y = rand()%(size*2200)*0.001-size*1.1;
		}
		// set other properties
		particle[i].pos_z = rand()%300*0.001;
		particle[i].size = 0.5+rand()%5*0.1;
		particle[i].red = 100*0.01;
		particle[i].green = 20*0.01;
		particle[i].blue = 0.0;
		particle[i].alpha = 0.0;
	}
	// detect collision with solid wall
	// left
	int restraints[4] = {0,0,0,0};
	for(int i=1; i<=size; i++){
		if((x-i < 0) || level->model[(int)(x-i)][(int)(y)].box == LEVEL_BOX){
			break;
		}
		else
			restraints[0] = i;
	}
	// right
	for(int i=1; i<=size; i++){
		if((x+i > level->cols) || level->model[(int)(x+i)][(int)(y)].box == LEVEL_BOX){
			break;
		}
		else
			restraints[1] = i;
	}
	// up
	for(int i=1; i<=size; i++){
		if((y+i >level->rows) || level->model[(int)(x)][(int)(y+i)].box == LEVEL_BOX){
			break;
		}
		else
			restraints[2] = i;
	}
	// down
	for(int i=1; i<=size; i++){
		if((y-i < 0) || level->model[(int)(x)][(int)(y-i)].box == LEVEL_BOX){
			break;
		}
		else
			restraints[3] = i;
	}
	// deactivate particles that break restrictions
	for(int i=0; i<particle_num; i++){
		// if it breaks left restrictions
		if((i%2 == 0) && (particle[i].pos_x < 0) && (fabs(particle[i].pos_x) > restraints[0])){
			particle[i].pos_x = 0;
			particle[i].pos_y = 0;
		}
		// if it breaks right restrictions
		else if((i%2 == 0) && (particle[i].pos_x > 0) && (fabs(particle[i].pos_x) > restraints[1])){
			particle[i].pos_x = 0;
			particle[i].pos_y = 0;
		}
		// if it breaks up restrictions
		else if((i%2 == 1) && (particle[i].pos_y > 0) && (fabs(particle[i].pos_y) > restraints[2])){
			particle[i].pos_x = 0;
			particle[i].pos_y = 0;
		}
		// if it breaks down restrictions
		else if((i%2 == 1) && (particle[i].pos_y < 0) && (fabs(particle[i].pos_y) > restraints[3])){
			particle[i].pos_x = 0;
			particle[i].pos_y = 0;
		}
		// correct position to match the level terrain
		Vertex v(this->p_X+particle[i].pos_x, this->p_Y+particle[i].pos_y, this->p_Z+particle[i].pos_z);
		level->heightCorrection(v);
		particle[i].pos_z = v.z - this->p_Z+0.4;
	}
}
